package pl.edu.pw.perg.compinfodb.datamodel;

import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;

import org.jdesktop.swingx.JXTable;

import pl.edu.pw.perg.compinfodb.command.IActiveModelListener;
import pl.edu.pw.perg.compinfodb.command.IModelModificationListener;
import pl.edu.pw.perg.compinfodb.command.IMutableTableModel;
import pl.edu.pw.perg.compinfodb.entities.ElementType;
import pl.edu.pw.perg.compinfodb.entities.Field;
import pl.edu.pw.perg.compinfodb.entities.PhysicalElement;
import pl.edu.pw.perg.compinfodb.entities.VirtualElement;
import pl.edu.pw.perg.compinfodb.ui.ColorRenderer;

public class CableDetailsTableModel implements TableModel,
		IElementTypeSelectionListener, ListSelectionListener,
		ISearchFilterListener, IRefreshListener, IMutableTableModel,
		FocusListener {

	private final String[] constColumnsNames = { "LABEL", 
			"LOCATION", "FROM", "FC#", "TO", "TC#" };
	private ElementDataList datalist;
	private String[] columnNames = new String[0];
	private List<TableModelListener> listeners = new LinkedList<TableModelListener>();
	private List<IPhysicalElementSelectionListener> peListeners = new ArrayList<IPhysicalElementSelectionListener>();
	private List<SearchTableModel> searchTableModels = new ArrayList<SearchTableModel>();
	private FlexibleTableColumnModel tcm = new FlexibleTableColumnModel(
			new ColorRenderer());
	private List<IActiveModelListener> activeModelListeners = new LinkedList<IActiveModelListener>();
	private List<IModelModificationListener> modelModificationListeners = new LinkedList<IModelModificationListener>();
	private boolean editable;
	private ElementType type;

	public CableDetailsTableModel(ElementDataList list) {
		datalist = list;
	}

	public void addTableModelListener(TableModelListener l) {
		listeners.add(l);

	}

	@SuppressWarnings("unchecked")
	public Class getColumnClass(int column) {
		return String.class;
	}

	public int getColumnCount() {
		return columnNames.length;
	}

	public String getColumnName(int columnIndex) {
		return columnNames[columnIndex];
	}

	public int getRowCount() {
		return datalist.size();
	}

	public Object getValueAt(int row, int column) {
		if (datalist.get(row) == null)
			return null;
		return datalist.get(row).getValue(columnNames[column]);
	}

	public boolean isCellEditable(int rowIndex, int columnIndex) {
		if (!editable)
			return false;
		return checkColumnEditability(columnIndex);
	}

	public void removeTableModelListener(TableModelListener l) {
		listeners.remove(l);

	}

	public void setValueAt(Object value, int rowIndex, int columnIndex) {
		if (value.equals(""))
			return;
		// datalist.get(rowIndex).setValue(getColumnName(columnIndex), value);
		datalist.setValueAt(rowIndex, getColumnName(columnIndex), value);
		modelModified();

	}

	public void selectionChanged(ElementType selectedElement) {
		setElementType(selectedElement);
	}

	public void selectionChanged(VirtualElement ve) {
		setElementType(ve.getElementType());

	}

	public void setElementType(ElementType type) {

		if (type == this.type)
			datalist.setTypeChanged(false);
		else {
			datalist.setTypeChanged(true);
			this.type = type;
			datalist.setTypeFilter(type);

			
			
			int attrsCount = 0;
			Iterator<Field> it = null;
			List<String> columns = new ArrayList<String>();

			if (type != null) {
				for (it = type.getFields().iterator(); it.hasNext();) {
					String string = (String) it.next().getFieldName();
					columns.add(string);
				}
			}
			columns.addAll(Arrays.asList(constColumnsNames));

			FlexibleTableColumnModel tcm = new FlexibleTableColumnModel(
					new ColorRenderer());

			columnNames = columns.toArray(new String[columns.size()]);
			recreateColumnModel();
		}
		datalist.search();
		

	}

	public void valueChanged(ListSelectionEvent e) {
		int row = ((ListSelectionModel) e.getSource())
				.getAnchorSelectionIndex();
		TableData td = datalist.get(row);
		if (td == null)
			return;
		PhysicalElement ce = td.getPe();
		for (IPhysicalElementSelectionListener pe : peListeners) {

			pe.selectionChanged(ce);
		}

	}

	public void addPhysicalElementSelectionListener(
			IPhysicalElementSelectionListener pes) {
		peListeners.add(pes);
	}

	public void filterChanged(Map<String, String> filter) {
		search(filter);
		reloadTable();

	}

	public void search(Map<String, String> filter) {
		datalist.search(filter);
	}

	public void reloadTable() {
		for (TableModelListener table : listeners) {
			table.tableChanged(new TableModelEvent(this));
		}
	}

	public void addColumnModelListener(SearchTableModel stm) {
		searchTableModels.add(stm);
	}

	public void recreateColumnModel() {
		for (TableModelListener l : listeners) {
			JXTable t = ((JXTable) l);
			tcm.setColumnNames(columnNames);
			t.setColumnModel(tcm);
			t.createDefaultColumnsFromModel();
			t.packAll();
			columnModelChanged();
		}
	}

	public void columnModelChanged() {
		for (SearchTableModel stm : searchTableModels) {
			stm.setColumnModel(tcm);
		}
	}

	public void refresh() {
		reloadTable();

	}

	public void addNew() {
		datalist.addNew();
		modelModified();
		reloadTable();
	}

	public boolean isModified() {
		return datalist.isModified();
	}

	public void save() {
		datalist.save();
		modelModified();
	}

	public void addActiveModelListener(IActiveModelListener activeModelListener) {
		activeModelListeners.add(activeModelListener);

	}

	public void addModelModificationListener(IModelModificationListener l) {
		modelModificationListeners.add(l);

	}

	public void setActive() {
		for (IActiveModelListener l : activeModelListeners) {
			l.setActiveModel(this);
		}

	}

	public void focusGained(FocusEvent e) {
		setActive();

	}

	public void focusLost(FocusEvent e) {
		// do nothing

	}

	private void modelModified() {
		for (IModelModificationListener l : modelModificationListeners) {
			l.modelModified(isModified());
		}
	}

	private boolean checkColumnEditability(int colIndex) {
		boolean flag = true;
		String name = columnNames[colIndex];
		for (int i = 0; i < constColumnsNames.length; i++) {
			if (name.equals(constColumnsNames[i])) {
				flag = false;
				break;
			}
		}
		if (name.equals("LABEL"))
			flag = true;
		return flag;
	}

	public void setEditable(boolean editable) {
		this.editable = editable;
	}

	public boolean isEditable() {
		return editable;
	}

}
